package com.zh.mycommon.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.Date;
import java.util.Locale;

public final class MyDateUtil {

    /**
     * 时间格式化为字符串
     *
     * @param pattern 格式
     * @param date    日期
     * @return 日期文本
     */
    public static String formatDate(String pattern, LocalDate date) {
        return DateTimeFormatter.ofPattern(pattern).format(date);
    }

    /**
     * 时间格式化为字符串
     *
     * @param pattern  格式
     * @param dateTime 时间
     * @return 时间文本
     */
    public static String formatDate(String pattern, LocalDateTime dateTime) {
        return DateTimeFormatter.ofPattern(pattern).format(dateTime);
    }

    /**
     * 时间字符串解析为时间对象
     *
     * @param pattern 格式
     * @param timeStr 时间文本
     * @return LocalDateTime
     */
    public static LocalDateTime parseLocalDateTime(String pattern, String timeStr) {
        //String To 时间
        return LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 时间字符串解析为时间对象
     *
     * @param pattern 格式
     * @param timeStr 时间文本
     * @return LocalDate
     */
    public static LocalDate parseLocalDate(String pattern, String timeStr) {
        //String To 时间
        return LocalDate.parse(timeStr, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 时间字符串解析为时间对象
     *
     * @param pattern 格式
     * @param timeStr 时间文本
     * @return LocalTime
     */
    public static LocalTime parseLocalTime(String pattern, String timeStr) {
        //String To 时间
        return LocalTime.parse(timeStr, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 时间字符串解析为时间对象
     *
     * @param pattern 格式
     * @param timeStr 时间文本
     * @return Date
     */
    public static Date parseDate(String pattern, String timeStr) {
        //String To 时间
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        try {
            return format.parse(timeStr);
        } catch (ParseException ex) {
            throw new IllegalArgumentException(ex);
        }
    }

    /**
     * LocalDateTime转Date
     *
     * @param dateTime 时间
     * @return Date
     */
    public static Date convertToDate(LocalDateTime dateTime) {
        return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * long转Date
     *
     * @param milliseconds 时间毫秒值
     * @return Date
     */
    public static Date convertToDate(long milliseconds) {
        return new Date(milliseconds);
    }

    /**
     * Date转LocalDateTime
     *
     * @param date 时间
     * @return LocalDateTime
     */
    public static LocalDateTime convertToLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    /**
     * long转LocalDateTime
     *
     * @param milliseconds 时间毫秒值
     * @return LocalDateTime
     */
    public static LocalDateTime convertToLocalDateTime(long milliseconds) {
        var instant = Instant.ofEpochMilli(milliseconds);
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

    /**
     * Date转毫秒值
     *
     * @param date 时间
     * @return 时间毫秒值
     */
    public static long toEpochMilli(Date date) {
        return date.getTime();
    }

    /**
     * Date转毫秒值
     *
     * @param dateTime 时间
     * @return 时间毫秒值
     */
    public static long toEpochMilli(LocalDateTime dateTime) {
        Instant instant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
        return instant.toEpochMilli();
    }

    /**
     * 获取指定日期所在的周次
     *
     * @return int
     */
    public static int weekOfYear(LocalDate date) {
        // 获取当前日期
        LocalDate today = LocalDate.now();
        // 定义一周的第一天为星期一
        WeekFields weekFields = WeekFields.of(Locale.getDefault());
        // 获取当前日期是一年的第几周
        return today.get(weekFields.weekOfWeekBasedYear());
    }

    /**
     * 获取今天所在的周次
     * 获取今天是这年的第几周
     *
     * @return int
     */
    public static int weekOfYear() {
        return weekOfYear(LocalDate.now());
    }

    /**
     * 获取今天的开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime startTimeOfDay() {
        return LocalDateTime.now().with(LocalTime.MIN);
    }

    /**
     * 获取今天的结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime endTimeOfDay() {
        return LocalDateTime.now().with(LocalTime.MAX);
    }

    /**
     * 获取本周的开始时间
     *
     * @return startTimeOfWeek
     */
    public static LocalDateTime startTimeOfWeek() {
        LocalDateTime nowDay = LocalDateTime.now().with(LocalTime.MIN);
        return nowDay.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
    }

    /**
     * 获取本周的结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime endTimeOfWeek() {
        LocalDateTime nowDay = LocalDateTime.now().with(LocalTime.MAX);
        return nowDay.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
    }

    /**
     * 获取本月的开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime startTimeOfMonth() {
        LocalDateTime nowDay = LocalDateTime.now().with(LocalTime.MIN);
        return nowDay.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 获取本月的结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime endTimeOfMonth() {
        LocalDateTime now = LocalDateTime.now().with(LocalTime.MAX);
        return now.with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 获取本月的第一天
     *
     * @return LocalDate
     */
    public static LocalDate firstDayOfMonth() {
        return LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 获取本月的最后一天
     *
     * @return LocalDate
     */
    public static LocalDate lastDayOfMonth() {
        return LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 获取本季度的开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime startTimeOfQuarter() {
        LocalDate now = LocalDate.now();
        LocalDate startQuarter = LocalDate.of(now.getYear(), now.getMonth().firstMonthOfQuarter(), 1);
        return startQuarter.atTime(LocalTime.MIN);
    }

    /**
     * 获取本季度的结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime endTimeOfQuarter() {
        LocalDate now = LocalDate.now();
        LocalDate endQuarter = LocalDate.of(now.getYear(), now.getMonth().firstMonthOfQuarter().plus(3), 1).minusDays(1);
        return endQuarter.atTime(LocalTime.MAX);
    }

    /**
     * 获取今年的开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime startTimeOfYear() {
        LocalDateTime now = LocalDateTime.now().with(LocalTime.MIN);
        return now.with(TemporalAdjusters.firstDayOfYear());
    }

    /**
     * 获取今年的结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime endTimeOfYear() {
        LocalDateTime now = LocalDateTime.now().with(LocalTime.MAX);
        return now.with(TemporalAdjusters.lastDayOfYear());
    }

    /**
     * 获取今年的第一天
     *
     * @return LocalDate
     */
    public static LocalDate firstDayOfYear() {
        return LocalDate.now().with(TemporalAdjusters.firstDayOfYear());
    }

    /**
     * 获取今年的最后一天
     *
     * @return LocalDate
     */
    public static LocalDate lastDayOfYear() {
        return LocalDate.now().with(TemporalAdjusters.lastDayOfYear());
    }


    /**
     * 调整起始时间到最近的下一个时刻
     *
     * @param time  原始时间
     * @param scale 标量（分钟） 5,10,15,20,30,60
     * @return 调整对齐后的时间
     */
    public static LocalDateTime adjustToNearestScale(LocalDateTime time, int scale) {
        if (scale == 0) {
            return time;
        }
        if (scale == 60) {
            return time.withMinute(0).withSecond(0).withNano(0).plusHours(1);
        }
        if (scale < 0 || scale > 60 || scale % 5 != 0 || 60 % scale != 0) {
            throw new IllegalArgumentException("scale值不合法：需满足 0<= scale <= 60, 且是5的倍数、60的约数 ");
        }
        if (scale > 30) { //此分支不会进入，但是暂时保留它
            scale = scale % 30; 
        }

        int minute = time.getMinute();

        if (minute % scale == 0) { // 已经是标量时间
            var value = minute;
            return time.withMinute(value).withSecond(0).withNano(0);
        } else {
            var value = ((minute / scale) + 1) * scale; //value 不可能>60
            //value < 60：取value
            if (value < 60) {
                return time.withMinute(value).withSecond(0).withNano(0);
            } else {
                return time.withMinute(0).withSecond(0).withNano(0).plusHours(1);
            }
        }
    }

    /*public static void main(String[] args) {
        LocalDateTime a = LocalDateTime.of(2025, 7, 10, 7, 48);

        for (int i = 0; i <= 30; i += 5) {
            try {
                var current = MyDateUtil.adjustToNearestScale(a, i);
                System.out.println(i + " -> current = " + current);
            } catch (Exception e) {
                System.err.println(e.getMessage());
            }
        }
    }*/
}